from typing import Optional, List, Dict
from fastapi import FastAPI, Request, Response, Form
from pydantic import BaseModel
import uvicorn

app = FastAPI()


class Girl(BaseModel):
    """数据验证是通过 pydantic 实现的，我们需要从中导入 BaseModel，然后继承它"""
    name: str
    age: Optional[str] = None
    length: float
    hobby: List[str]  # 对于 Model 中的 List[str] 我们不需要指定 Query（准确的说是 Field）


@app.post("/girl")
async def read_girl(girl: Girl):
    # girl 就是我们接收的请求体，它需要通过 json 来传递，并且这个 json 要有上面的四个字段（age 可以没有）
    # 通过 girl.xxx 的方式我们可以获取和修改内部的所有属性
    return dict(girl)  # 直接返回 Model 对象也是可以的


@app.post("/girl1")
async def read_girl(request: Request):
    # 是一个协程，所以需要 await
    data = await request.body()
    print(data)


@app.post("/girl2/{user_id}")
async def read_girl(user_id,
                    q: str,
                    girl: Girl):
    return {"user_id": user_id, "q": q, **dict(girl)}


@app.post("/girl3/{user_id}")
async def read_girl(user_id,
                    request: Request):
    q = request.query_params.get("q")
    data: Dict = await request.json()
    data.update({"user_id": user_id, "q": q})
    return data


@app.post("/girl4")
async def girl(request: Request):
    # 此时 await request.json() 报错，因为是通过 data 参数传递的，相当于 form 表单提交
    # 如果是通过 json 参数传递，那么 await request.form() 会得到一个空表单
    form = await request.form()
    return [form.get("name"), form.getlist("age")]


@app.post("/user")
async def get_user(username: str = Form(...),
                   password: str = Form(...)):
    return {"username": username, "password": password}


if __name__ == "__main__":
    uvicorn.run("main2:app", host="0.0.0.0", port=5555)
